﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Bridge.Workflow.Application.Contracts;
using Bridge.Workflow.Domain;
using Bridge.Workflow.Domain.Workflows;
using Bridge.Workflow.Extension;
using Bridge.Workflow.Workflows.Dtos;
using Newtonsoft.Json;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq;
using Volo.Abp.Users;
using WorkflowCore.Interface;

namespace Bridge.Workflow.Application
{
    /// <summary>
    /// 工作流管理
    /// </summary>
    public class WorkflowService : ApplicationService, IWorkflowService
    {
        private readonly ICurrentUser _currentUser;
        private readonly IAbpWorkflowManager _abpWorkflowManager;
        private readonly IAsyncQueryableExecuter _asyncQueryableExecuter;
        private readonly IRepository<PersistedWorkflow, string> _workflowRepository;
        private readonly IRepository<PersistedWorkflowAuditor, string> _auditorRepos;

        private readonly IWorkflowRegistry _registry;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="currentUser"></param>
        /// <param name="workflowRepository"></param>
        public WorkflowService(ICurrentUser currentUser,
            IAbpWorkflowManager abpWorkflowManager,
            IAsyncQueryableExecuter asyncQueryableExecuter,
            IWorkflowRegistry registry,
            IRepository<PersistedWorkflow, string> workflowRepository,
            IRepository<PersistedWorkflowAuditor, string> auditorRepos)
        {
            _currentUser = currentUser;
            _abpWorkflowManager = abpWorkflowManager;
            _workflowRepository = workflowRepository;
            _asyncQueryableExecuter = asyncQueryableExecuter;
            _registry = registry;
            _auditorRepos = auditorRepos;
        }

        /// <summary>
        /// 测试
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task TestAsync()
        {
            var f = _registry.GetDefinition("3a04976c-4006-5de7-c1e7-c7cc912c5955", 1);
            var fff = _registry.GetAllDefinitions();
            string gf = "";
        }


        /// <summary>
        /// 启动工作流
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task StartAsync(StartWorkflowInput input)
        {
            await _abpWorkflowManager.StartWorlflow(input.Id, input.Version, input.Inputs);
        }

        /// <summary>
        /// 发布事件
        /// </summary>
        /// <param name="input"></param>
        public async Task PublicEvent(PublishEventInput input)
        {
            await _abpWorkflowManager.PublishEventAsync(input.EventName, input.EventKey, input.EventData);
        }

        /// <summary>
        /// 我参与的流程
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<MyWorkflowListOutput>> GetPageListAsync(WorkflowListInput input)
        {
            //获取我参与的流程
            var data = await _auditorRepos.GetListAsync(s => s.UserId == _currentUser.Id && s.Status != EnumAuditStatus.UnAudited);
            var ids = data.Select(s => s.WorkflowId).Distinct().ToList();
            var query = (await _workflowRepository.GetQueryableAsync()).Where(u => u.CreatorId == _currentUser.Id || ids.Contains(u.Id));

            query = query.WhereIf(!string.IsNullOrEmpty(input.Title), u => u.WorkflowDefinition.Title.Contains(input.Title))
             .WhereIf(!string.IsNullOrEmpty(input.CurrentStepName), u => u.ExecutionPointers.OrderBy(i => i.StartTime).Last().StepName.Contains(input.CurrentStepName))
             .WhereIf(!string.IsNullOrEmpty(input.CreatorName), u => u.CreateUserIdentityName.Contains(input.CreatorName))
             .WhereIf(!string.IsNullOrEmpty(input.CreationTimeStart), u => u.CreationTime >= Convert.ToDateTime(input.CreationTimeStart))
             .WhereIf(!string.IsNullOrEmpty(input.CreationTimeEnd), u => u.CreationTime <= Convert.ToDateTime(input.CreationTimeEnd))
             .WhereIf(input.Statuses != null && input.Statuses.Any(), u => input.Statuses.Contains((int)u.Status));
            var result = await query.OrderByDescending(u => u.CreationTime).ToPagedResultAsync(input, u => new MyWorkflowListOutput()
            {
                Title = u.WorkflowDefinition.Title,
                Version = u.Version,
                Id = u.Id,
                Status = u.Status,
                CompleteTime = u.CompleteTime,
                CreationTime = u.CreationTime,
                CurrentStepName = u.ExecutionPointers.OrderBy(i => i.StartTime).Last().StepName,
                Nodes = u.WorkflowDefinition.Nodes,
                CreatorId = u.CreatorId ?? Guid.Empty,
                BusinessData = JsonConvert.DeserializeObject<WorkflowData>(u.Data),
                CreatorName = u.CreateUserIdentityName
            });
            return result;
        }

        public async Task<PagedResultDto<MyWorkflowListOutput>> GetProcessingPageListViewAsync(WorkflowListInput input)
        {
            //获取我参与的流程
            var data = await _auditorRepos.GetListAsync(s =>  s.Status != EnumAuditStatus.UnAudited);
            var ids = data.Select(s => s.WorkflowId).Distinct().ToList();
            var query = (await  _workflowRepository.GetQueryableAsync());

            query = query.Where(u => u.CreatorId == _currentUser.Id || ids.Contains(u.Id))
                .WhereIf(!string.IsNullOrEmpty(input.Title), u => u.WorkflowDefinition.Title.Contains(input.Title))
                .WhereIf(!string.IsNullOrEmpty(input.CurrentStepName), u => u.ExecutionPointers.OrderBy(i => i.StartTime).Last().StepName.Contains(input.CurrentStepName))
                .WhereIf(!string.IsNullOrEmpty(input.CreatorName), u => u.CreateUserIdentityName.Contains(input.CreatorName))
                .WhereIf(!string.IsNullOrEmpty(input.CreationTimeStart), u => u.CreationTime >= Convert.ToDateTime(input.CreationTimeStart))
                .WhereIf(!string.IsNullOrEmpty(input.CreationTimeEnd), u => u.CreationTime <= Convert.ToDateTime(input.CreationTimeEnd))
                .WhereIf(input.Statuses != null && input.Statuses.Any(), u => input.Statuses.Contains((int)u.Status));
            var result = await query.OrderByDescending(u => u.CreationTime).ToPagedResultAsync(input, u => new MyWorkflowListOutput()
            {
                Title = u.WorkflowDefinition.Title,
                Version = u.Version,
                Id = u.Id,
                Status = u.Status,
                CompleteTime = u.CompleteTime,
                CreationTime = u.CreationTime,
                CurrentStepName = u.ExecutionPointers.OrderBy(i => i.StartTime).Last().StepName,
                Nodes = u.WorkflowDefinition.Nodes,
                CreatorId = u.CreatorId ?? Guid.Empty,
                BusinessData = JsonConvert.DeserializeObject<WorkflowData>(u.Data),
                CreatorName = u.CreateUserIdentityName
            });
            return result;
        }

        /// <summary>
        /// 获取流程详情
        /// </summary>
        /// <param name="input">待审核ID</param>
        /// <returns></returns>
        public async Task<WorkflowDto> GetDetailsAsync(string id)
        {
            if (id.IsNullOrEmpty())
            {
                return null;
            }
            var temp = await _asyncQueryableExecuter.FirstOrDefaultAsync((await _workflowRepository.GetQueryableAsync()).Where(u => u.Id == id).Select(u => new
            {
                u.Id,
                u.Version,
                u.WorkflowDefinitionId,
                u.WorkflowDefinition.Title,
                u.CreateUserIdentityName,
                u.CreationTime,
                u.WorkflowDefinition.Inputs,
                u.Data,
                u.CompleteTime,
                u.Status,
                u.WorkflowDefinition.Nodes
            }));
            var workflowExecutionRecords = (await _auditorRepos.GetQueryableAsync()).Where(u => u.WorkflowId == id).Select(s => new WorkflowExecutionRecord()
            {
                ExecutionPointerId = s.ExecutionPointer.Id,
                EndTime = s.ExecutionPointer.EndTime,
                StartTime = s.ExecutionPointer.StartTime,
                StepId = s.ExecutionPointer.StepId,
                StepName = s.ExecutionPointer.StepName,
            });
            WorkflowDto result = new WorkflowDto()
            {
                Id = temp.Id,
                Data = temp.Data.FromJsonString<Dictionary<string, object>>(),

                CompleteTime = temp.CompleteTime,
                Status = temp.Status,
                Title = temp.Title,
                CreationTime = temp.CreationTime,
                UserName = temp.CreateUserIdentityName,
                Version = temp.Version,
                WorkflowDefinitionId = temp.WorkflowDefinitionId,
                Inputs = temp.Inputs,
                ExecutionRecords = workflowExecutionRecords
            };

            foreach (var item in result.ExecutionRecords)
            {
                item.StepTitle = temp.Nodes.FirstOrDefault(i => i.Key == item.StepName)?.Title;
            }
            return result;
        }
    }
}
